// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once
#include <mutex>               //for unique_lock
#include <condition_variable>  //for cv_status
namespace bfcallocator {

class OrtMutex {
  std::mutex mtx_;

 public:
  constexpr OrtMutex() = default;
  ~OrtMutex() = default;
  OrtMutex(const OrtMutex&) = delete;
  OrtMutex& operator=(const OrtMutex&) = delete;

  void lock() { mtx_.lock(); }
  bool try_lock() noexcept { return mtx_.try_lock(); }
  void unlock() noexcept { mtx_.unlock(); }

  using native_handle_type = std::mutex*;
  native_handle_type native_handle() { return &mtx_; }
};

// class OrtCondVar {
//   nsync::nsync_cv native_cv_object = NSYNC_CV_INIT;

//  public:
//   constexpr OrtCondVar() noexcept = default;

//   ~OrtCondVar() = default;
//   OrtCondVar(const OrtCondVar&) = delete;
//   OrtCondVar& operator=(const OrtCondVar&) = delete;

//   void notify_one() noexcept { nsync::nsync_cv_signal(&native_cv_object); }
//   void notify_all() noexcept { nsync::nsync_cv_broadcast(&native_cv_object); }

//   void wait(std::unique_lock<OrtMutex>& lk);
//   template <class _Predicate>
//   void wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred);

//   /**
//    * returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
//    * cv_status::no_timeout.
//    * @param cond_mutex A unique_lock<OrtMutex> object.
//    * @param rel_time A chrono::duration object that specifies the amount of time before the thread wakes up.
//    * @return returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
//    * cv_status::no_timeout
//    */
//   template <class Rep, class Period>
//   std::cv_status wait_for(std::unique_lock<OrtMutex>& cond_mutex, const std::chrono::duration<Rep, Period>& rel_time);
//   using native_handle_type = nsync::nsync_cv*;
//   native_handle_type native_handle() { return &native_cv_object; }

//  private:
//   void timed_wait_impl(std::unique_lock<OrtMutex>& __lk,
//                        std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>);
// };

// template <class _Predicate>
// void OrtCondVar::wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred) {
//   while (!__pred()) wait(__lk);
// }

// template <class Rep, class Period>
// std::cv_status OrtCondVar::wait_for(std::unique_lock<OrtMutex>& cond_mutex,
//                                     const std::chrono::duration<Rep, Period>& rel_time) {
//   // TODO: is it possible to use nsync_from_time_point_ ?
//   using namespace std::chrono;
//   if (rel_time <= duration<Rep, Period>::zero())
//     return std::cv_status::timeout;
//   using SystemTimePointFloat = time_point<system_clock, duration<long double, std::nano> >;
//   using SystemTimePoint = time_point<system_clock, nanoseconds>;
//   SystemTimePointFloat max_time = SystemTimePoint::max();
//   steady_clock::time_point steady_now = steady_clock::now();
//   system_clock::time_point system_now = system_clock::now();
//   if (max_time - rel_time > system_now) {
//     nanoseconds remain = duration_cast<nanoseconds>(rel_time);
//     if (remain < rel_time)
//       ++remain;
//     timed_wait_impl(cond_mutex, system_now + remain);
//   } else
//     timed_wait_impl(cond_mutex, SystemTimePoint::max());
//   return steady_clock::now() - steady_now < rel_time ? std::cv_status::no_timeout : std::cv_status::timeout;
// }
};  // namespace bfcallocator
